package com.ruoyi.system.service.impl;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.ruoyi.common.config.EncryptConfig;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.vo.Result;
import com.ruoyi.system.domain.vo.SendVerifyCodeVo;
import com.ruoyi.system.service.IVerifyCodeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.servlet.http.HttpServletRequest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private EncryptConfig encryptConfig;

    @Value("${spring.mail.username}")
    private String from;

    @Value("${spring.mail.nickname}")
    private String nickname;

    @Override
    public void sendVerifyCode(SendVerifyCodeVo sendVerifyCodeVo) {
        String verifyCode = RandomStringUtils.randomAlphanumeric(4);
        if (Objects.nonNull(redisTemplate.opsForValue().get("send_verify_code:" + sendVerifyCodeVo.getPhoneOrEmail()))) {
            throw new ServiceException("当前邮箱或手机号已发送验证码，尚未过期");
        }
        // 判断是否是邮箱
        if (Validator.isEmail(sendVerifyCodeVo.getPhoneOrEmail())) {
            this.sendVerifyCodeEmail(sendVerifyCodeVo.getPhoneOrEmail(), verifyCode, "verifyCode");
        } else if (PhoneUtil.isMobile(sendVerifyCodeVo.getPhoneOrEmail())) {
            throw new ServiceException("暂不支持发送手机验证码");
        }else {
            throw new ServiceException("邮箱或手机号格式错误");
        }
        // 2分钟有效期
        redisTemplate.opsForValue().set("send_verify_code:" + sendVerifyCodeVo.getPhoneOrEmail(), verifyCode, 2, TimeUnit.MINUTES);
        // 判断是否是手机号
    }

    @Override
    public void sendVerifyCodeEmail(String to, String verifyCode, String htmlFileName) {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            helper.setFrom(new InternetAddress(MimeUtility.encodeText(nickname, CharsetUtil.UTF_8, "B")+'<'+from+'>').toString());
            helper.setTo(to);
            helper.setSubject("ChatShop邮箱验证码");
            //创建一个 Thymeleaf 模板引擎实例
            TemplateEngine templateEngine = new TemplateEngine();
            // 创建一个 Thymeleaf 模板解析器
            ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
            templateResolver.setPrefix("templates/");
            templateResolver.setSuffix(".html");
            templateEngine.setTemplateResolver(templateResolver);
            // 获取模板文件名
            // 创建一个 Thymeleaf 上下文对象
            Context context = new Context();
            context.setVariable("verifyCode", Arrays.asList(verifyCode.split("")));
            // 渲染模板并获取结果
            String content = templateEngine.process(htmlFileName, context);
            helper.setText(content, true);
            javaMailSender.send(mimeMessage);
        } catch (Exception e) {
            log.error("验证码发送失败：", e);
            throw new ServiceException("验证码发送失败，请联系管理员处理");
        }
    }

    @Override
    public Result<?> submitVerify(SendVerifyCodeVo sendVerifyCodeVo) {
        if (ObjectUtil.notEqual(sendVerifyCodeVo.getVerifyCode(), redisTemplate.opsForValue().get("send_verify_code:" + sendVerifyCodeVo.getPhoneOrEmail()))) {
            throw new ServiceException("验证码错误，请重新提交");
        }
        // 设置客户端token  1天过期
        String clientToken = encryptConfig.symmetricEncryt(sendVerifyCodeVo.getPhoneOrEmail());
        // 保存到redis中
        redisTemplate.opsForValue().set(clientToken, sendVerifyCodeVo.getPhoneOrEmail(), 1, TimeUnit.DAYS );
        return Result.OK("验证码验证成功", clientToken);
    }

    @Override
    public String checkClientToken(HttpServletRequest request) {
        String clientToken = request.getHeader("clientToken");
        if (StrUtil.isBlank(clientToken)) {
            throw new AuthorizationServiceException("无效客户Token");
        }
        String email = redisTemplate.opsForValue().get(clientToken);
        if (StrUtil.isBlank(clientToken)) {
            throw new AuthorizationServiceException("无效客户Token");
        }
        return email;
    }

}
